﻿
#include <unordered_map>
#include "playerinfo_mgr.h"
#include "ManagerHelper.h"
#include "../share/proxyclient_service.h"
#include "../share/sql/mysql_connection.h"
#include "../share/sql/mysql_resultset.h"
#include "../share/common_define.h"
#include "script_define.h"
#include "../share/MessageDef.h"
#include "../share/string_common.h"
#include "../share/GameHostManager.h"
#include "scene_logic.h"
#include "MapSlot.h"
#include "../share/time_module.h"
#include "../share/tplmgr.h"
#include "scene_event.h"


void CPlayerInfo::FillToJson(Json::Value& info)
{
	info.clear();
	info["playerid"] = m_playerId;
	info["account"] = m_accountId;
	info["name"] = m_name;
	info["level"] = m_level;
	info["heroid"] = m_heroid;
	info["photo"] = m_photoframe;
	info["afc"] = m_afc;
	info["unionid"] = m_union_id;
	info["unionname"] = m_union_name;
	info["title"] = m_title;
	info["heroskin"] = m_heroSkinId;
	info["vip"] = m_vip;
	Player* player = CSceneLogic::GetInstance().GetPlayerByPlayerID(m_playerId);
	if (player == NULL)
	{
		info["online"] = 0;
	}
	else
	{
		info["online"] = 1;
	}
}

bool CPlayerInfo::parseFromJson(const Json::Value& playerinfo)
{
	m_playerId = atol(playerinfo["playerid"].asString().c_str());
	m_accountId = atol(playerinfo["account"].asString().c_str());
	m_name = playerinfo["name"].asString();
	m_level = playerinfo["level"].asUInt();
	m_heroid = playerinfo["heroid"].asUInt();
	m_photoframe = playerinfo["photo"].asUInt();
	m_afc = playerinfo["afc"].asUInt();
	m_union_id = playerinfo["unionid"].asUInt();
	m_union_name = playerinfo["unionname"].asString();
	m_title = playerinfo["title"].asUInt();
	m_heroSkinId = playerinfo["heroskin"].asUInt();
	m_vip = playerinfo["vip"].asUInt();

	return true;
}


void CPlayerGuild::LoadFromJson(Json::Value& playerguild_json)
{
	last_leave_guild_time_ = playerguild_json["last_leave"].asInt();
}

void CPlayerGuild::SaveToJson(Json::Value& playerguild_json)
{
	playerguild_json["last_leave"] = last_leave_guild_time_;
}

int32_t CPlayerGuild::GetJoinCDLimitTime()
{
	const CUnionLvCfg* union_cfg = CTPLManager::GetInstance().GetUnionCfgByLevel(1);
	if ( union_cfg == NULL )
	{
		return last_leave_guild_time_;
	}
	int32_t join_limit_time = last_leave_guild_time_ + union_cfg->guild_quit_cd;
	return join_limit_time;
}


CPlayerInfoMgr::CPlayerInfoMgr(void)
{
	save_list_.clear();
	role_id_max_ = 10000;
}

CPlayerInfoMgr::~CPlayerInfoMgr()
{

}

bool CPlayerInfoMgr::Initialize(void)
{
	player_leave_game_event += OnEventPlayerLeaveGame;
	return LoadDB();
}

void CPlayerInfoMgr::Finalize(void)
{
	for (TRoleIDMap::iterator iter = role_id_map_.begin(); iter != role_id_map_.end(); ++iter)
	{
		CPlayerInfo* player_info = iter->second;
		if (NULL != player_info)
		{
			delete player_info;
		}
	}
	role_id_map_.clear();
	role_id_set_.clear();
	role_name_map_.clear();
	save_list_.clear();
	account_id_map_.clear();
	player_leave_game_event -= OnEventPlayerLeaveGame;
}

bool CPlayerInfoMgr::LoadDB()
{
	std::string host = GameHostManager::GetInstance().GetGameDBIP();
	std::string prot = GameHostManager::GetInstance().GetGameDBProt();
	std::string user = GameHostManager::GetInstance().GetGameDBUser();
	std::string pwd = GameHostManager::GetInstance().GetGameDBPwd();
	std::string dbname = GameHostManager::GetInstance().GetGameDBName();
	sql::Connection conn;
	if (conn.Init(host,prot,user,pwd,dbname) == false)
	{
		LOG_WARN("default","init db conn : %s:%s:%s:%s:%s failed", host.c_str(), prot.c_str(), user.c_str(), pwd.c_str(), dbname.c_str());
		return false;
	}
	// 加载数据库中的玩家数据的一部分
	std::string load_sql = "SELECT playerId,account,name,level,heroId, heroSkinId, vip, photoFrame,afc,unionId,unionName, unionPosition,title, UNIX_TIMESTAMP(lastLogoutTime) as logouttime FROM tb_player_info WHERE account>'9999';";
	sql::ResultSet  result_set;
	sql::ResultSet* res = conn.ExecuteQuery(load_sql.c_str(), result_set);
	if (res == NULL)
	{
		LOG_WARN("default","load player info failed!");
		return false;
	}
	while (res->next() == true)
	{
		CPlayerInfo* player_info = new CPlayerInfo();
		if ( player_info == NULL )
		{
			continue;
		}
		player_info->set_accountId(res->getUint("account"));
		player_info->set_playerId(res->getUint("playerId"));
		player_info->set_name(res->getStringStr("name"));
		player_info->set_level(res->getUint("level"));
		player_info->set_heroid(res->getUint("heroId"));
		player_info->set_heroSkinId(res->getUint("heroSkinId"));
		player_info->set_vip(res->getUint("vip"));
		player_info->set_photoframe(res->getUint("photoFrame"));
		player_info->set_afc(res->getUint("afc"));
		player_info->set_union_id(res->getUint("unionId"));
		player_info->set_union_name(res->getStringStr("unionName"));
		player_info->set_union_pos(res->getInt("unionPosition"));
		player_info->set_title(res->getUint("title"));
		player_info->set_last_logout_time(res->getInt("logouttime"));
		
		AddRole(player_info);
	}
	result_set.close();

	LOG_INFO("default","load player num %d", GetPlayerCount());


	std::string load_detail_sql = "SELECT playerId, friend, playerguild, arena_rank_continuity FROM tb_player_offline;";
	res = conn.ExecuteQuery(load_detail_sql.c_str(), result_set);
	if (res == NULL)
	{
		LOG_ERROR("default","load player offline data failed");
		return false;
	}
	LOG_INFO("default", "load player offline data %d", res->GetRowCount());
	while (res->next() == true)
	{
		Json::Value info;
		info.clear();
		uint32_t playerId = res->getUint("playerId");
		
		std::string firend_str = res->getStringStr("friend");
		info["friend"] = firend_str;
		
		// playerguild 直接在C++中处理

		std::string arena_rank_continuity_str = res->getStringStr("arena_rank_continuity");
		info["arena_rank_continuity"] = arena_rank_continuity_str;

		std::string data = JsonWriter(info);
		int32_t ret = 0;
		MapSlot::GetInstance().GetLuaManagerPtr()->RunScriptFunctionWithRet(LUA_FriendManagerScript,
			LUA_LoadFromPB, playerId, data.c_str(), &ret);
		if ( ret != 0 )
		{
			LOG_ERROR("default","load player offline data failed plyaerid[%d]", playerId);
		}

		// 不在Lua中处理的字段
		std::string playerguild_str = res->getStringStr("playerguild");
		Json::Value player_guild_json;
		JsonReader(playerguild_str, player_guild_json);
		CPlayerInfo* playerinfo = CPlayerInfoMgr::GetInstance().GetPlayerInfoByPlayerID(playerId);
		if ( playerinfo != NULL )
		{
			playerinfo->PlayerGuild().LoadFromJson(player_guild_json);
		}
	}
	result_set.close();

	conn.Close();
	return true;
}

void CPlayerInfoMgr::GetRecommendFriend(uint32_t playerid, const std::string& friendlist, std::string& recommandlist)
{
	std::vector<uint32_t> friend_;
	common::SplitString< uint32_t >(friendlist, ";", friend_);
	std::unordered_map<uint32_t, int32_t> friend_map;
	for ( int32_t i = 0 ; i < (int32_t)friend_.size(); ++i )
	{
		friend_map.insert(std::make_pair(friend_[i], 1));
	}
	
	std::set<uint32_t> recommand;
	CSceneLogic::GetInstance().GetRecommendFriend(playerid, friend_map, recommand);

	if ( recommand.size() >= 12 )
	{
		transformRecommend(recommandlist, recommand);
		return;
	}

	TRoleIDSet::iterator it = role_id_set_.begin();
	int32_t pos = RAND(role_id_set_.size() + 1);
	for (int32_t i = 0; i < pos && it != role_id_set_.end(); ++i) {
		++it;
	}
	for (int32_t i = 0; i < (int32_t)role_id_set_.size(); ++i, ++it) {
		if (it == role_id_set_.end()) {
			it = role_id_set_.begin();
		}

		CPlayerInfo* playerinfo = GetPlayerInfoByPlayerID(*it);
		if ( playerinfo == NULL )
		{
			continue;
		}

		// 已经是好友的过滤
		auto iter = friend_map.find(playerinfo->get_playerId());
		if (iter != friend_map.end())
		{
			continue;
		}

		//过滤自己
		if (playerinfo->get_playerId() == playerid)
		{
			continue;
		}

		// 过滤掉不符合等级的
		if (playerinfo->get_level() <= 10)
		{
			continue;
		}

		recommand.insert(playerinfo->get_playerId());

		if (recommand.size() >= 12)
		{
			break;
		}
	}
	transformRecommend(recommandlist, recommand);
}

CPlayerInfo* CPlayerInfoMgr::GetPlayerInfoByPlayerID(uint32_t playerid)
{
	TRoleIDMap::iterator it = role_id_map_.find(playerid);
	if ( it == role_id_map_.end() )
	{
		return NULL;
	}
	return it->second;
}

CPlayerInfo* CPlayerInfoMgr::GetPlayerInfoByPlayerName(const std::string& name)
{
	TRoleNameMap::iterator it = role_name_map_.find(name);
	if (it == role_name_map_.end())
	{
		return NULL;
	}
	return it->second;
}

void CPlayerInfoMgr::transformRecommend(std::string& recommandlist, std::set<uint32_t>& recommand)
{
	Json::Value mjson;
	Json::Value info;
	
	mjson.clear();
	for (std::set<uint32_t>::iterator it = recommand.begin(); it != recommand.end(); ++it )
	{
		CPlayerInfo* playerinfo = GetPlayerInfoByPlayerID(*it);
		if ( playerinfo == NULL )
		{
			continue;
		}
		
		playerinfo->FillToJson(info);
		mjson.append(info);
	}
	recommandlist = JsonWriter(mjson);
}

void CPlayerInfoMgr::GetPlayerInfo(uint32_t playerid, std::string& playerinfo_str)
{
	playerinfo_str.clear();
	CPlayerInfo* playerinfo = GetPlayerInfoByPlayerID(playerid);
	if ( playerinfo == NULL )
	{
		return;
	}
	Json::Value info;
	playerinfo->FillToJson(info);

	playerinfo_str = JsonWriter(info);
}

void CPlayerInfoMgr::GetPlayerInfoByName(const std::string& name, std::string& playerinfo_str)
{
	playerinfo_str.clear();
	CPlayerInfo* playerinfo = GetPlayerInfoByPlayerName(name);
	if (playerinfo == NULL)
	{
		return;
	}
	Json::Value info;
	playerinfo->FillToJson(info);
	playerinfo_str = JsonWriter(info);
}

void CPlayerInfoMgr::PlayerChanged(int32_t player_id, int32_t change_time /*= 0*/)
{
	time_t cur_time = CUR_SEC;
	SDirtyPlayer dirty_role;
	dirty_role.player_id_ = player_id;
	dirty_role.add_time_ = (change_time != 0) ? change_time : cur_time;
	GetInstance().save_list_.push_back(dirty_role);
}

int32_t CPlayerInfoMgr::SaveRoles(int32_t max_save_count)
{
	int32_t save_count = 0;
	int32_t save_list_count = save_list_.size();
	time_t cur_time = CUR_SEC;
	for (int32_t i = 0; (i < save_list_count) && (save_list_.empty() == false); ++i )
	{
		SDirtyPlayer dirty_role = save_list_.front();
		int32_t role_id = dirty_role.player_id_;;
		save_list_.pop_front();
		CPlayerInfo* role = GetPlayerInfoByPlayerID(role_id);
		if (NULL == role)
		{
			continue;
		}

		if (role->last_save_time() >= dirty_role.add_time_)
		{
			continue;
		}

		if ((role->last_save_time() + 60) >= cur_time)
		{
			PlayerChanged(role_id, dirty_role.add_time_);
			continue;
		}
		//std::string str_data;
		char str_data[1024 * 200] = {0};
		
		MapSlot::GetInstance().GetLuaManagerPtr()->RunScriptFunctionWithRet(LUA_FriendManagerScript,
			LUA_SaveToPB, role_id, str_data);

		LOG_INFO("default","gate role %d save, %s", role_id, str_data);

		Json::Value playerguild_json;
		role->PlayerGuild().SaveToJson(playerguild_json);

		Json::Value data_cpp;
		data_cpp["playerguild"] = playerguild_json;

		save_count++;
		
		role->set_last_save_time(cur_time);

		Json::Value send_to_db;
		send_to_db["account"] = role->get_accountId();
		send_to_db["playerId"] = role->get_playerId();
		send_to_db["msgid"] = G2D_PLAYER_OFFLINE_SAVE_REQ;
		send_to_db["data"] = str_data;
		send_to_db["data_cpp"] = JsonWriter(data_cpp);

		std::string m_send = JsonWriter(send_to_db);
		send_2_db(G2D_PLAYER_OFFLINE_SAVE_REQ, m_send, role->get_playerId());

		if (save_count >= max_save_count) 
			break;
	}
	return save_count;
}

void CPlayerInfoMgr::AddNewPlayer(std::string& playerinfo)
{
	Json::Value player;
	JsonReader(playerinfo, player);
	CPlayerInfo* playerinfo_c = new CPlayerInfo();
	if (playerinfo_c == NULL)
	{
		return;
	}
	if (playerinfo_c->parseFromJson(player) == false)
	{
		delete playerinfo_c;
		playerinfo_c = NULL;
		return;
	}
	uint32_t playerId = playerinfo_c->get_playerId();
	uint32_t accountId = playerinfo_c->get_accountId();

	role_id_map_.insert(std::make_pair(playerId, playerinfo_c));
	role_name_map_.insert(std::make_pair(playerinfo_c->get_name(), playerinfo_c));
	role_id_set_.insert(playerId);
	account_id_map_.insert(std::make_pair(accountId, playerId));
	CheckRefreshRoleIDMax(playerId);
}

int32_t CPlayerInfoMgr::GetPlayerIDbyAccountID(uint32_t account_id)
{
	TAccountIDMap::iterator it = account_id_map_.find(account_id);
	if ( it == account_id_map_.end() )
	{
		return 0;
	}
	return it->second;
}

int32_t CPlayerInfoMgr::GetAccoutRoleIDMax()
{
	return role_id_max_++;
}

int32_t CPlayerInfoMgr::CheckRefreshRoleIDMax(int32_t role_id)
{
	int32_t real_playerid = role_id & 0x000FFFFF;
	role_id_max_ = (role_id_max_ >= real_playerid) ? role_id_max_ : real_playerid;
	return role_id_max_;
}

void CPlayerInfoMgr::AddRole(CPlayerInfo* player_info)
{
	if (player_info == NULL)
	{
		LOG_ERROR("default","ADDRole err player_info is null");
		return;
	}
	uint32_t playerId = player_info->get_playerId();
	if (playerId == 0)
	{
		LOG_ERROR("default", "ADDRole err playerId is 0");
		return;
	}
	uint32_t accountId = player_info->get_accountId();
	if (accountId == 0)
	{
		LOG_ERROR("default", "ADDRole err accountId is 0");
		return;
	}
	role_id_map_.insert(std::make_pair(playerId, player_info));
	role_name_map_.insert(std::make_pair(player_info->get_name(), player_info));
	role_id_set_.insert(playerId);
	account_id_map_.insert(std::make_pair(accountId, playerId));
	CheckRefreshRoleIDMax(playerId);
}

void CPlayerInfoMgr::PlayerChangeName(std::string& old_name, CPlayerInfo& playerinfo)
{
	TRoleNameMap::iterator it = role_name_map_.find(old_name);
	if ( it != role_name_map_.end() )
	{
		role_name_map_.erase(it);
	}
	role_name_map_.insert(std::make_pair(playerinfo.get_name(), &playerinfo));
}

void CPlayerInfoMgr::OnEventPlayerLeaveGame(Player& player)
{
	CPlayerInfo* playerinfo = CPlayerInfoMgr::GetInstance().GetPlayerInfoByPlayerID(player.GetPlayerId());
	if ( playerinfo != NULL )
	{
		playerinfo->set_last_logout_time(CUR_SEC);
	}

	// 通知map， 玩家离开了游戏
	Json::Value m_jv;
	m_jv["msgid"] = login_player_quit_game_notify;
	m_jv["_gate_fd"] = player.GetSocketId();
	std::string send_str = JsonWriter(m_jv);
	send_2_map(login_player_quit_game_notify, send_str);
}

Player* CPlayerInfoMgr::GetPlayerByClientKey(uint64_t client_key)
{
	uint32_t player_id = client_key - player_key_start;
	//Player* player = CGameObjManager::GetInstance().GetObjectByID<Player*>(player_id);
	Player *player = CSceneLogic::GetInstance().GetPlayerByPlayerID(player_id);
	return player;
}

